Redux Toolkit 官方的推薦使用的Redux工具,用於提高 Redux 開發。
它包含幾個實用功能,可簡化最常見的 Redux 用例,包括存儲設置、定義 reducer、不可變更新邏輯,甚至無需手動編寫任何動作創建者或動作類型即可一次創建整個狀態Slice。 它還包括最廣泛使用的 Redux 插件,例如用於異步邏輯的 Redux Thunk 和用於編寫選擇器函數的 Reselect,以便您可以立即使用它們。
說到這部分我們可以回想一下前面幾篇製作純 redux 環境時都遇到哪些繁瑣的工作?
這樣一整套繁瑣的流程,如果是大型專案的話有道理,但如果只是一般的 crud (ex: todo list) 這樣的小型專案,做起來就顯得很麻煩。
這就是選擇 redux toolkit 的好處了,一個 slice 裡面整合了 initialState, action, reducer,等一下使用時更能理解為何官方也推薦這類的做法。
為了方便大家理解簡化的過程,我們會另外起一個資料夾來做相同的處理,這裡的 demo 我會放在我 github 的 rtk folder 下面,那們練習的話可以自己找位置,也是會從 npm init 開始:
npm init -y
接著安裝 redux & redux-toolkit :
npm install redux @reduxjs/toolkit
or
yarn add redux @reduxjs/toolkit
因為 redux-toolkit 的 slice 會整合 action, reducer, types…., 所以我這次用 features 的資料夾來裝所有 redux 相關的檔案,然後我們一樣先從 store 做初始設定,首先在 feature 的資料夾內新增一個 store.js 的檔案:
// features/store.js
const { configureStore } = require('@reduxjs/toolkit');
const store = configureStore({
reducer: {}
})
module.exports = {
store,
}
使用 configureStore 來替換掉原本的 createStore,接著我麼先去搬遷原本的 action & reducer,將這些東西轉換成新的整合寫法 Slice.js,這邊我們新增一個叫 Slices 的資料夾,並試著搬遷其中的coffee看看,於 slices 資料夾下新增 coffeeSlice.js 並如下:
// features/slices/coffeeSlice.js
const createSlice = require('@reduxjs/toolkit').createSlice;
// 同 only 的 coffeeReducer initial state
const initialState = {
numOfCoffee: 20
}
const coffeeSlice = createSlice({
name: 'coffee',
initialState,
reducers: {
// 這裡固定會有 sate & action 兩參數,直接對應於上面的 state
coffeeOrdered: (state, action) => {
state.numOfCoffee = state.numOfCoffee - action.payload
return state;
},
coffeeRestocked: (state, action) => {
state.numOfCoffee = state.numOfCoffee + action.payload
return state;
},
}
})
// 這邊就要注意 default 的情況下輸出 reducer 對應的 action function 會從 coffeeActions 引入
module.exports = coffeeSlice.reducer;
module.exports.coffeeActions = coffeeSlice.actions;
在 createSlice 內 actions 對應的就會是你 reducers 裡面定義的 function name,最後的 export 也很重要,作為 store 的整合器,你需要做的是輸出 slice.reducer,也就是說於前一步 store.js 需要引入的是 default 值,而在 dispatch 要使用的則為 coffeeActions。
那麼,有了 reducer 之後我們回過頭來整併進 store:
// store.js
const configureStore = require('@reduxjs/toolkit').configureStore;
const coffeeReducer = require('./slices/coffeeSlice');
const store = configureStore({
reducer: {
coffee: coffeeReducer,
}
})
module.exports = { store }
至此我們已經完成 action → action creator → reducer,對你沒看錯,一個完整的 redux data flow 已經完成,不相信嗎?我們一樣做一個 index.js 來測試看看指令,於根目錄下新增 index.js,如下:
// ./index.js
const { store } = require('./features/store');
const coffeeActions = require('./features/slices/coffeeSlice').coffeeActions;
console.log('Initial State', store.getState());
const unsubscribe = store.subscribe(() => console.log('更新', store.getState()));
store.dispatch(coffeeActions.coffeeOrdered(1));
store.dispatch(coffeeActions.coffeeOrdered(4));
store.dispatch(coffeeActions.coffeeRestocked(10));
unsubscribe();
然後於終端機 node index.js,應該會有以下訊息:
Initial State { coffee: { numOfCoffee: 20 } }
更新 { coffee: { numOfCoffee: 19 } }
更新 { coffee: { numOfCoffee: 15 } }
更新 { coffee: { numOfCoffee: 25 } }
恭喜,你已經完成原本於 redux 需要做的兩個檔案的量了,下一篇我們陸續將其他的 reducer 也用相同的方式正並進來。